/*
妇添小有一个很厉害的技能：发现吃的！如果有好吃的东西，不论多远，只要一闻就能知道在哪里。这天他刚刚在程设rejudge完，忽然鼻子一抽——有吃的！他决定马上赶去吃这么好吃的东西。

语文男为了考验妇添小的品味，在路中间放了很多馒头，看他会不会饿的先吃馒头。妇添小当然不会让这种雕虫小计得逞！为了保持自己的品味，他决定绕开所有的馒头。Eureka受到妇添小邀请，运用绝世法力构造了很多传送点，任意两个传送点之间都能瞬移（当然传不传，传到哪里都可以随心所欲）。妇添小每次移动只能走上下左右四个方向（瞬移除外，并且瞬移不耗费时间）。现在，妇添小最短多长时间能吃到好吃的东西呢？

（当然，为了出题我们隐瞒了一些事实：不仅好吃的不见了，路上的馒头竟然也不翼而飞了，这真真是个悲伤的故事T.T）

输入：

第一行包含两个数字n, m（1 <= n, m <= 2000）

接下来包含n行，每行m个字符，表示现在的地图。'.'表示空地，'M‘表示馒头，‘E’表示传送点，'N'表示妇添小所在的位置，'C'表示吃的。'N'和‘C'在地图中出现且仅出现一次。

输出：

一个数字，表示妇添小最快能多长时间吃到好吃的。如果永远吃不到，只能说明传送点不够多，输出“Bad Eureka”。

提示：如果时间显示是0.004等很短的时间，但是最后评测为TLE，这时候实际上是因为开的数组过大，超出了内存限制。
*/


#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif
#if defined(_WIN32) && !defined(__cplusplus)
#define inline __inline
#endif

#include <stdio.h>
#include <memory.h>

#define MAX_N 2005
#define MAX_M 2005

#define MAX_DIST 0xffffffff

#define max(a,b)    (((a) > (b)) ? (a) : (b))
#define min(a,b)    (((a) < (b)) ? (a) : (b))

/* 函数结果状态代码 */
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
typedef int Status; /* Status是函数的类型,其值是函数结果状态代码，如OK等 */
typedef int BOOL; /* Boolean是布尔类型,其值是TRUE或FALSE */
typedef unsigned int DWORD;

typedef struct
{
	short X;
	short Y;
}Point;


#define MAX_QUEUE_SIZE 4000000
typedef Point QElemType;
// rear 指向下一个空位
typedef struct
{
	int front, rear;
	QElemType data[MAX_QUEUE_SIZE];
}CircularQueue;

BOOL IsQueueEmpty(const CircularQueue *Q)
{ /* 若Q为空队列,则返回TRUE,否则返回FALSE */
	return Q->front == Q->rear;
}

BOOL IsQueueFull(const CircularQueue *Q)
{ /* 若Q为空队列,则返回TRUE,否则返回FALSE */
	return Q->front == (Q->rear + 1) % MAX_QUEUE_SIZE;
}

Status InitQueue(CircularQueue *Q)
{ /* 构造一个空队列Q */
	Q->front = 0;
	Q->rear = 0;
	return OK;
}

Status EnQueue(CircularQueue *Q, QElemType e)
{ /* 插入元素e为Q的新的队尾元素 */
	if (IsQueueFull(Q)) return ERROR;
	Q->data[Q->rear] = e;
	++Q->rear;
	Q->rear = Q->rear % MAX_QUEUE_SIZE;
	return OK;
}

Status DeQueue(CircularQueue *Q, QElemType *e)
{ /* 若队列不空,删除Q的队头元素,用e返回其值,并返回OK,否则返回ERROR */
	if (IsQueueEmpty(Q)) return ERROR;
	*e = Q->data[Q->front];
	++Q->front;
	Q->front = Q->front % MAX_QUEUE_SIZE;
	return OK;
}

Status ClearQueue(CircularQueue *Q)
{
	return InitQueue(Q);
}

Status DestroyQueue(CircularQueue *Q)
{
	return ClearQueue(Q);
}


char map[MAX_N][MAX_M];
DWORD dist[MAX_N][MAX_M];
CircularQueue queue;

static inline BOOL CanGo(char map[MAX_N][MAX_M], int x, int y)
{
	if (map[y][x] != 0 && map[y][x] != 'M') return TRUE;
	else return FALSE;
}

int GetDistOfNearestE(char map[MAX_N][MAX_M], DWORD dist[MAX_N][MAX_M], Point start)
{
	memset(dist, MAX_DIST, sizeof(DWORD) * MAX_N * MAX_M);	
	InitQueue(&queue);
	EnQueue(&queue, start);
	dist[start.Y][start.X] = 0;

	int iDist = -1;
	while (!IsQueueEmpty(&queue))
	{
		Point curPoint;
		DeQueue(&queue, &curPoint);

		if (map[curPoint.Y][curPoint.X] == 'E')
		{
			iDist = dist[curPoint.Y][curPoint.X];
			goto end;
		}
		else
		{
			Point adjacentPoint[] = {{curPoint.X - 1, curPoint.Y},{curPoint.X + 1, curPoint.Y},{curPoint.X, curPoint.Y + 1},{curPoint.X, curPoint.Y - 1}};
			for (int i = 0; i < 4; i++)
			{
				Point *p = &adjacentPoint[i];
				if (CanGo(map, p->X, p->Y) && dist[p->Y][p->X] == MAX_DIST)
				{
					EnQueue(&queue, *p);
					dist[p->Y][p->X] = dist[curPoint.Y][curPoint.X] + 1;
				}
			}
		}
	}
end:
	DestroyQueue(&queue);
	return iDist;
}

int GetDistOfTwoPoints(char map[MAX_N][MAX_M], DWORD dist[MAX_N][MAX_M], Point start, Point end)
{
	memset(dist, MAX_DIST, sizeof(DWORD) * MAX_N * MAX_M);
	InitQueue(&queue);
	EnQueue(&queue, start);
	dist[start.Y][start.X] = 0;

	int iDist = -1;
	while (!IsQueueEmpty(&queue))
	{
		Point curPoint;
		DeQueue(&queue, &curPoint);

		if (curPoint.X == end.X && curPoint.Y == end.Y)
		{
			iDist = dist[curPoint.Y][curPoint.X];
			goto end;
		}
		else
		{
			Point adjacentPoint[] = {{curPoint.X - 1, curPoint.Y},{curPoint.X + 1, curPoint.Y},{curPoint.X, curPoint.Y + 1},{curPoint.X, curPoint.Y - 1}};
			for (int i = 0; i < 4; i++)
			{
				Point *p = &adjacentPoint[i];
				if (CanGo(map, p->X, p->Y) && dist[p->Y][p->X] == MAX_DIST)
				{
					EnQueue(&queue, *p);
					dist[p->Y][p->X] = dist[curPoint.Y][curPoint.X] + 1;
				}
			}
		}
	}
end:
	DestroyQueue(&queue);
	return iDist;
}

int GetDist(char map[MAX_N][MAX_M], DWORD dist[MAX_N][MAX_M], Point start, Point end)
{
	int iDist1 = GetDistOfTwoPoints(map, dist, start, end);
	int iDist2 = GetDistOfNearestE(map, dist, start);
	if (iDist2 >= 0)
	{
		int temp = GetDistOfNearestE(map, dist, end);
		if (temp >= 0) iDist2 += temp;
		else iDist2 = -1;
	}


	if (iDist1 < 0 && iDist2 < 0) return -1;
	else if (iDist1 < 0) return iDist2;
	else if (iDist2 < 0) return iDist1;
	else return min(iDist1, iDist2);
}

int main()
{
	int m, n;


	Point start, end;

	memset(map, 0, sizeof(map));

	scanf("%d%d\n", &n, &m);
	for (int i = 1; i < n + 1; i++)
	{
		for (int j = 1; j < m + 1; j++)
		{
			char ch = getchar();
			map[i][j] = ch;
			if (ch == 'N')
			{
				start.X = j;
				start.Y = i;
			}
			else if (ch == 'C')
			{
				end.X = j;
				end.Y = i;
			}
		}
		getchar();
	}

	int result = GetDist(map, dist, start, end);

	if (result == -1) printf("Bad Eureka\n");
	else printf("%d\n", result);

	return 0;
}

